

import java.io.File;
import java.io.FileInputStream;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

import Graph.Graph;
import Graph.GraphNode;

import soot.Unit;
import soot.toolkits.graph.UnitGraph;

public class XMLTranslator {

	public List<MyNode> list = new ArrayList<MyNode>();
	DocumentBuilderFactory docFactory;
	DocumentBuilder docBuilder;
	String xmlPath;
	
	public NodeList allNodes;
	public List<GraphNode> allNodesList = new ArrayList<GraphNode>();
	
	public XMLTranslator(String path){
		this.docFactory = DocumentBuilderFactory.newInstance();
		xmlPath = "C:\\Framework\\xml\\"+path;
		this.allNodesList = new ArrayList<GraphNode>();
	}
	

	public Graph readXMLToTree(){
		
		Graph tree = null;
		List<GraphNode> treeNodeList = new ArrayList<GraphNode>();
		List<GraphNode> exitsNodeList = new ArrayList<GraphNode>();
		GraphNode rootNode = null;
		
		try{
			docBuilder = docFactory.newDocumentBuilder();
			InputStream is = new FileInputStream(xmlPath);
			Document doc = docBuilder.parse(is);
			
			Element root = doc.getDocumentElement();
			allNodes = root.getChildNodes();
			
			
			for(int i=0;i<allNodes.getLength();i++){
				Node node = allNodes.item(i);
				String strId = node.getAttributes().getNamedItem("id").getNodeValue().toString();
				int id = Integer.parseInt(strId);
				String content = node.getAttributes().getNamedItem("content").getNodeValue().toString();
				GraphNode myNode = new GraphNode(id, content);
				this.allNodesList.add(myNode);
			}
			
			
			for(int i=allNodesList.size()-1;i>=0;i--){
				Node node = allNodes.item(i);
				String strId = node.getAttributes().getNamedItem("id").getNodeValue().toString();
				int id = Integer.parseInt(strId);
				String content = node.getAttributes().getNamedItem("content").getNodeValue().toString();
				GraphNode myNode = new GraphNode(id, content);
				
				/*XML get Children*/
				NodeList children = node.getChildNodes();
				if(content.contains("return")){
					exitsNodeList.add(myNode);
				}
				
				if(id == 0){
					rootNode = myNode;
				}
				
				if(children.getLength() > 0 ){
					if(children.getLength() == 1){
						int sub1 = Integer.parseInt(node.getChildNodes().item(0).getTextContent());
						GraphNode leftNode = getMyNodeById(sub1,treeNodeList);
						myNode.setLeftNode(leftNode);
						myNode.setChildrenNum(1);
					}
					
					else{
						int sub1 = Integer.parseInt(node.getChildNodes().item(0).getTextContent());
						GraphNode leftNode = getMyNodeById(sub1,treeNodeList);
						
						int sub2 = Integer.parseInt(node.getChildNodes().item(1).getTextContent());
						GraphNode rightNode = getMyNodeById(sub2,treeNodeList);
						
						myNode.setLeftNode(leftNode);
						myNode.setRightNode(rightNode);
						
						myNode.setChildrenNum(2);
					}
				}
				
				treeNodeList.add(myNode);
			}

			tree = new Graph(rootNode);
			tree.setExits(exitsNodeList);
			tree.setAllNodes(treeNodeList);
			tree.getAllPath();
			tree.printAllPath();
			
		} catch (ParserConfigurationException pce) {
      		pce.printStackTrace();
      	} catch (SAXException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		return tree;
    		
	}
	
	private GraphNode getMyNodeById(int id, List<GraphNode> treeNodeList){
		GraphNode node = null;
		for(int i=0;i<treeNodeList.size();i++){
			GraphNode currentNode = treeNodeList.get(i);
			if(currentNode.getId() == id){
				return currentNode;
			}
		}
		return node;
	}
	
	public void writeXML(UnitGraph graph){
		try
		{
	  		docBuilder = docFactory.newDocumentBuilder();
	  		Document doc = docBuilder.newDocument(); 
	  		
	  		Element rootElement = doc.createElement("statements");
	  		doc.appendChild(rootElement);
	  				
	  		Iterator<Unit> units = graph.iterator();
	  		int index  = 0;
	  		while(units.hasNext()){
	  			String id = String.valueOf(index);
	  			Unit unit = units.next();
		  		Element beanElement = doc.createElement("statment");
		  		beanElement.setAttribute("content", unit.toString());
		  		System.out.println(unit.toString());
		  		beanElement.setAttribute("id", id);
		  		java.util.List<Unit> children = graph.getSuccsOf(unit);
		  		
		  		if(children.size()>0){
		  			for(int i=0;i<children.size();i++){
		  				Element nextStatement = doc.createElement("NextStatement");
			  			String subId = String.valueOf(getIndex(graph, children.get(i)));
			  			nextStatement.setTextContent(subId);
			  			beanElement.appendChild(nextStatement);
		  			}
		  		}
		  		
		  		rootElement.appendChild(beanElement);
		  		
		      	// write the content into xml file
		      	TransformerFactory transformerFactory = TransformerFactory.newInstance();
		      	Transformer transformer = transformerFactory.newTransformer();
		      	DOMSource source = new DOMSource(doc);
		      	StreamResult result = new StreamResult(new File(xmlPath));
		      	transformer.transform(source, result);
		      	index++;
	  		}
	      	
      	} catch (ParserConfigurationException pce) {
      		pce.printStackTrace();
      	} catch (TransformerException tfe) {
      		tfe.printStackTrace();
      	}
    		System.out.println("File saved!");
		}
	
	private int getIndex(UnitGraph graph, Unit unit){
		Iterator<Unit> units = graph.iterator();
		int i = 0;
		while(units.hasNext()){
  			Unit next = units.next();
  			if(unit.equals(next))
  				return i;
  			i++;
		}
		return -1;
	}
	
	
}